package models

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/BertoldVdb/go-ais"
)

// ShipInfo 船舶信息
type ShipInfo struct {
	Channel   string  `json:"channel"`             //Channel 通道 A/B
	MMSI      string  `json:"mmsi,omitempty"`      //MMSI
	Name      string  `json:"name,omitempty"`      //船名
	Callsign  string  `json:"callsign,omitempty"`  //呼号
	IMO       string  `json:"imo,omitempty"`       //IMO Numbber
	CnName    string  `json:"cnName,omitempty"`    //中文船名
	MID       MID     `json:"mid,omitempty"`       //MID
	ISO       string  `json:"iso,omitempty"`       //2位国家代码
	Country   string  `json:"country,omitempty"`   //国家
	ShipType  uint8   `json:"shipType,omitempty"`  //船舶类型
	Draught   float32 `json:"draught,omitempty"`   // 吃水深度 (米) - 0.1 to 25.5 metres
	FixType   uint8   `json:"fixTtype,omitempty"`  //电子定位装置类型 0:未规定（默认值） 1:GPS 2:GLONASS 3:GPS/GLONASS组合 4:Loran-C 5:Chayka 6:综合导航系统 7:正在研究 8:Galileo 9-14:未使用 15:内部GNSS
	Eta       string  `json:"eta,omitempty"`       //估计到达时间
	Dest      string  `json:"dest,omitempty"`      //目的地
	Length    int32   `json:"length,omitempty"`    //船长
	Width     int32   `json:"width,omitempty"`     //船宽
	GPSRefPos []int32 `json:"gpsRefPos,omitempty"` //定位天线参考位置
}

// ParseMID 解析 AIS MMSI MID
func ParseMID(s *ais.Header) MID {
	mmsi := fmt.Sprintf("%d", s.UserID)
	return parseMID(mmsi)
}

// getMID 海事识别数字 (Maritime Identification Digits)
// 2~7 开头的3位数字, 0 表示未知
// MMSI类型		结构
//
//		个别船只	M I D X X X X X X
//		船只组		0 M I D X X X X X
//		岸站或岸站  0 0 M I D X X X X
//	 SAR飞机		1 1 1 M I D X X X
//	 导航辅助	9 9 M I D X X X X
func parseMID(mmsi string) MID {
	var _m int
	prefix := true
	index := 0
	for _, c := range mmsi {
		if prefix && (c == '0' || c == '1' || c == '9') {
			//跳过 0开头的字符
			continue
		} else {
			prefix = false
		}
		if index < 3 {
			_m = _m*10 + int(c-'0')
			index++
		} else {
			break
		}
	}
	return MID(_m)
}

// formatEta 格式化 ETA 数据
func formatEta(eta ais.FieldETA) string {
	const defaultEta = "-"
	if eta.Month == 0 || eta.Day == 0 {
		return defaultEta
	}

	return fmt.Sprintf("%d-%d %d:%02d", eta.Month, eta.Day, eta.Hour, eta.Minute)
}

// ToShipInfo 解析 AIS 静态数据
func ToShipInfo(s *ais.ShipStaticData) *ShipInfo {
	mmsi := fmt.Sprintf("%d", s.UserID)
	mid := parseMID(mmsi)
	iso := mid.GetAlpha2()
	return &ShipInfo{
		Channel:   "",
		MMSI:      mmsi,
		Name:      strings.TrimSpace(s.Name),
		Callsign:  strings.TrimSpace(s.CallSign),
		IMO:       strconv.FormatUint(uint64(s.ImoNumber), 10),
		MID:       mid,
		ISO:       iso,
		Country:   mid.GetCnName(),
		ShipType:  s.Type,
		Draught:   float32(s.MaximumStaticDraught),
		FixType:   s.FixType,
		Eta:       formatEta(s.Eta),
		Dest:      strings.TrimSpace(s.Destination),
		Length:    int32(s.Dimension.A + s.Dimension.B),
		Width:     int32(s.Dimension.C + s.Dimension.D),
		GPSRefPos: []int32{int32(s.Dimension.A), int32(s.Dimension.B), int32(s.Dimension.C), int32(s.Dimension.D)},
	}
}

// ToShipInfo 解析 AIS 静态数据
func (s *ShipInfo) FromMsg5(r *ais.ShipStaticData) *ShipInfo {
	if s == nil {
		s = &ShipInfo{}
	}
	mmsi := fmt.Sprintf("%d", r.UserID)
	mid := parseMID(mmsi)
	iso := mid.GetAlpha2()

	s.Channel = ""
	s.MMSI = mmsi
	s.Name = strings.TrimSpace(r.Name)
	s.Callsign = strings.TrimSpace(r.CallSign)
	s.IMO = strconv.FormatUint(uint64(r.ImoNumber), 10)
	s.MID = mid
	s.ISO = iso
	s.Country = mid.GetCnName()
	s.ShipType = r.Type
	s.Draught = float32(r.MaximumStaticDraught)
	s.FixType = r.FixType
	s.Eta = formatEta(r.Eta)
	s.Dest = strings.TrimSpace(r.Destination)
	s.Length = int32(r.Dimension.A + r.Dimension.B)
	s.Width = int32(r.Dimension.C + r.Dimension.D)
	s.GPSRefPos = []int32{int32(r.Dimension.A), int32(r.Dimension.B), int32(r.Dimension.C), int32(r.Dimension.D)}
	return s
}

// ToHashMap 生成 船舶信息 Map (map[string]interface{})
func ToHashMap(r *ais.ShipStaticData) map[string]interface{} {
	mmsi := fmt.Sprintf("%d", r.UserID)
	mid := parseMID(mmsi)
	gpsrefPos, _ := json.Marshal([]int32{int32(r.Dimension.A), int32(r.Dimension.B), int32(r.Dimension.C), int32(r.Dimension.D)})
	return map[string]interface{}{
		"MMSI":      mmsi,
		"Name":      strings.TrimSpace(r.Name),
		"Callsign":  strings.TrimSpace(r.CallSign),
		"IMO":       fmt.Sprintf("%d", r.ImoNumber),
		"MID":       int32(mid),
		"Country":   mid.GetCnName(),
		"ShipType":  r.Type,
		"Draught":   float32(r.MaximumStaticDraught),
		"Eta":       formatEta(r.Eta),
		"Dest":      strings.TrimSpace(r.Destination),
		"Length":    int32(r.Dimension.A + r.Dimension.B),
		"Width":     int32(r.Dimension.C + r.Dimension.D),
		"GPSRefPos": gpsrefPos,
	}
}
